package com.efeichong.oss;

import com.ksyun.ks3.dto.Ks3Object;
import com.ksyun.ks3.dto.ObjectMetadata;
import com.ksyun.ks3.http.HttpMethod;
import com.ksyun.ks3.service.Ks3;
import com.ksyun.ks3.service.Ks3Client;
import com.ksyun.ks3.service.request.GeneratePresignedUrlRequest;
import com.ksyun.ks3.service.request.GetObjectRequest;
import com.ksyun.ks3.service.request.PutObjectRequest;
import lombok.Cleanup;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author lxk
 * @date 2020/11/5
 * @description 金山云oss
 */
@Slf4j

public class JsOssService extends AbstractOssService implements OssService {

    public JsOssService(@NonNull OssConfigS3 config) {
        super(config);
    }

    @SneakyThrows
    @Override
    public String upload(MultipartFile file, String bucketName, String folderName, @NonNull String suffix) {
        String uuid = UUIDUtils.getId();
        if (!suffix.startsWith(".")) {
            suffix = "." + suffix;
        }
        String newFileName = uuid + suffix;

        String key = StringUtils.isBlank(folderName) ? newFileName : folderName + "/" + newFileName;
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        ks3Client.setEndpoint(endpoint);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.getSize());
        metadata.setContentEncoding("UTF-8");
        metadata.setContentType(FileType.getContentType(suffix));

        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file.getInputStream(), metadata);
        ks3Client.putObject(putObjectRequest);
        newFileName = "https://" + bucketName + "." + endpoint + "/" + key;
        return newFileName;
    }

    @SneakyThrows
    @Override
    public String upload(byte[] bytes, String bucketName, String folderName, String suffix) {
        String uuid = UUIDUtils.getId();
        if (!suffix.startsWith(".")) {
            suffix = "." + suffix;
        }
        String newFileName = uuid + suffix;

        String key = StringUtils.isBlank(folderName) ? newFileName : folderName + "/" + newFileName;
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        ks3Client.setEndpoint(endpoint);

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(bytes.length);
        metadata.setContentEncoding("UTF-8");
        metadata.setContentType(FileType.getContentType(suffix));

        @Cleanup InputStream inputStream = IoUtils.byteToInputStream(bytes);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, metadata);
        ks3Client.putObject(putObjectRequest);
        newFileName = "https://" + bucketName + "." + endpoint + "/" + key;
        return newFileName;
    }

    @Override
    public List<String> upload(MultipartFile[] files, String bucketName, String folderName, String suffix) {
        List<String> urls = Arrays.stream(files).map(file -> upload(file, bucketName, folderName, suffix)).collect(Collectors.toList());
        return urls;
    }

    @Override
    public UploadUrl getUploadUrl(String bucketName, String folderName, String suffix) {
        if (!suffix.startsWith(".")) {
            suffix = "." + suffix;
        }
        String uuid = UUIDUtils.getId();
        String newFileName = uuid + suffix;
        String key = StringUtils.isBlank(folderName) ? newFileName : folderName + "/" + newFileName;
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        ks3Client.setEndpoint(endpoint);
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
        request.setBucket(bucketName);
        request.setKey(key);
        request.setMethod(HttpMethod.PUT);
        request.setContentType(FileType.getContentType(suffix));
        // 这里设置签名在半个小时后过期
        DateTime expireTime = DateTime.now().plusMinutes(30);
        request.setExpiration(expireTime.toDate());
        String url = ks3Client.generatePresignedUrl(request);
        return new UploadUrl(url, bucketName, endpoint, key);
    }

    @Override
    public List<UploadUrl> getUploadUrls(String bucketName, String folderName, String suffix, Integer num) {
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        ks3Client.setEndpoint(endpoint);
        if (!suffix.startsWith(".")) {
            suffix = "." + suffix;
        }

        List<UploadUrl> urls = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            String uuid = UUIDUtils.getId();
            String newFileName = uuid + suffix;

            String key = StringUtils.isBlank(folderName) ? newFileName : folderName + "/" + newFileName;
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest();
            request.setBucket(bucketName);
            request.setKey(key);
            request.setMethod(HttpMethod.PUT);
            // 这里设置签名在半个小时后过期
            DateTime expireTime = DateTime.now().plusMinutes(30);
            request.setExpiration(expireTime.toDate());
            String url = ks3Client.generatePresignedUrl(request);
            urls.add(new UploadUrl(url, bucketName, endpoint, key));
        }
        return urls;
    }

    @SneakyThrows
    @Override
    public byte[] download(String url) {
        String bucketName = url.substring(url.indexOf("://") + 3, url.indexOf("."));
        String objectName = url.substring(url.lastIndexOf("/") + 1);
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectName);
        Ks3Object ossObject = ks3Client.getObject(getObjectRequest).getObject();
        @Cleanup InputStream inputStream = ossObject.getObjectContent();
        return IoUtils.inputStreamToByte(inputStream);
    }

    @SneakyThrows
    @Override
    public ZipOutputStream batchDownload(OutputStream outputStream, List<String> urls) {
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        @Cleanup ZipOutputStream zos = new ZipOutputStream(outputStream);
        urls.forEach(FunctionWithException.wrapper(url -> {
            String bucketName = url.substring(url.indexOf("://") + 3, url.indexOf("."));
            String objectName = url.substring(url.lastIndexOf("/") + 1);
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectName);
            Ks3Object ossObject = ks3Client.getObject(getObjectRequest).getObject();
            @Cleanup InputStream inputStream = ossObject.getObjectContent();
            byte[] buf = new byte[1024];
            zos.putNextEntry(new ZipEntry(url.substring(url.lastIndexOf("/") + 1)));
            int len;
            while ((len = inputStream.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            zos.closeEntry();
        }));
        return zos;
    }

    @Override
    public void delete(String url) {
        String bucketName = url.substring(url.indexOf("://") + 3, url.indexOf("."));
        String objectName = url.substring(url.lastIndexOf("/") + 1);
        Ks3 ks3Client = new Ks3Client(accessKeyId, accessKeySecret);
        ks3Client.deleteObject(bucketName, objectName);
    }

    @Override
    public void batchDelete(List<String> urls) {
        urls.stream().forEach(url -> delete(url));
    }
}
